home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / haeberli / libgutil / expr.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  7KB  |  358 lines

  1. /*
  2.  * expr_eval: expression evaluator - converts ascii string to floating point
  3.  * Works by top-down predictive parsing.
  4.  * Most of the routines gobble characters and advance global string pointer s.
  5.  * Sets global expr_err if an error occurs.
  6.  *
  7.  * supports: parentheses, % for mod, ^ for pow, elementary functions,
  8.  * constants pi and e, variable base constants
  9.  *
  10.  * Paul Heckbert    18 April 1988
  11.  */
  12.  
  13. static char rcsid[] = "$Header: expr.c,v 4.0 89/12/13 22:02:21 ph Locked $";
  14.  
  15. #include "ctype.h"
  16. #include "math.h"
  17.  
  18. #include "simple.h"
  19. #include "expr.h"
  20. #define space() for (; isspace(*s); s++)
  21.  
  22. double expr_eval();
  23. static double expr(), term(), factor(), signednumber(), number(),
  24.     paren(), posconst(), expt();
  25. static char *s0, *s;
  26. int expr_error;
  27.  
  28. static eq(
  29.     int n,
  30.     char *a, char *b);
  31.  
  32. static error(
  33.     char *s, 
  34.     int len,
  35.     char *err);
  36.  
  37. static paren2(
  38.     double *x, double *y);
  39.  
  40. static digit(
  41.     int c);
  42.  
  43. static prints(
  44.     int n,
  45.     char *s);
  46.  
  47. #ifdef MAIN
  48. main(ac, av)
  49. int ac;
  50. char **av;
  51. {
  52.     double x;
  53.  
  54.     if (ac!=2) exit(1);
  55.     x = expr_eval(av[1]);
  56.     printf(">> %g\n", x);
  57. }
  58. #endif
  59.  
  60. int expr_eval_int(str)
  61. char *str;
  62. {
  63.     double x;
  64.  
  65.     x = expr_eval(str);
  66.     /* do unsigned double to signed int conversion: */
  67.     return x>MAXINT ? x+2.*MININT : x;
  68. }
  69.  
  70. long expr_eval_long(str)
  71. char *str;
  72. {
  73.     double x;
  74.  
  75.     x = expr_eval(str);
  76.     /* do unsigned double to signed long conversion: */
  77.     return x>MAXLONG ? x+2.*MINLONG : x;
  78. }
  79.  
  80. double expr_eval(str)
  81. char *str;
  82. {
  83.     double x;
  84.  
  85.     s0 = s = str;
  86.     expr_error = EXPR_GOOD;
  87.     x = expr();
  88.     if (*s) {
  89.     error(s, 1, "garbage in expression");
  90.     expr_error = s==s0 ? EXPR_BAD : EXPR_SOSO;
  91.     }
  92.     return x;
  93. }
  94.  
  95. static double expr()
  96. {
  97.     double x;
  98.  
  99.     for (x=term();;) {
  100.     space();
  101.     switch (*s) {
  102.         case '+': s++; x += term(); break;
  103.         case '-': s++; x -= term(); break;
  104.         default: return x;
  105.     }
  106.     }
  107. }
  108.  
  109. static double term()
  110. {
  111.     double x, y;
  112.  
  113.     for (x=factor();;) {
  114.     space();
  115.     switch (*s) {
  116.         case '*': s++; x *= factor(); break;
  117.         case '/': s++; x /= factor(); break;
  118.         case '%': s++; y = factor(); x = x-floor(x/y)*y; break;
  119.         default: return x;
  120.     }
  121.     }
  122. }
  123.  
  124. static double factor()
  125. {
  126.     double x;
  127.  
  128.     for (x=signednumber();;) {
  129.     space();
  130.     switch (*s) {
  131.         case '^': s++; return pow(x, factor());    /* right-associative */
  132.         default: return x;
  133.     }
  134.     }
  135. }
  136.  
  137. static double signednumber()
  138. {
  139.     space();
  140.     switch (*s) {
  141.     case '-': s++; return -signednumber();
  142.     case '+': s++; return signednumber();
  143.     default: return number();
  144.     }
  145. }
  146.  
  147. static double number()
  148. {
  149.     char *func;
  150.     int n;
  151.     double x, y;
  152.  
  153.     space();
  154.     if (isdigit(*s) || *s=='.') return posconst();
  155.     if (*s=='(') return paren();
  156.  
  157.     if (isalpha(*s)) {
  158.     func = s;
  159.     for (s++; isalpha(*s) || isdigit(*s); s++);
  160.     n = s-func;    /* length of funcname */
  161.  
  162.     if (eq(n, func, "pi"))        return PI;
  163.     if (eq(n, func, "e"))        return exp(1.);
  164.  
  165.     if (eq(n, func, "sqrt"))    return sqrt(paren());
  166.     if (eq(n, func, "exp"))        return exp(paren());
  167.     if (eq(n, func, "log"))        return log(paren());
  168.     if (eq(n, func, "pow"))        {paren2(&x, &y); return pow(x, y);}
  169.  
  170.     if (eq(n, func, "sin"))        return sin(paren());
  171.     if (eq(n, func, "cos"))        return cos(paren());
  172.     if (eq(n, func, "tan"))        return tan(paren());
  173.     if (eq(n, func, "asin"))    return asin(paren());
  174.     if (eq(n, func, "acos"))    return acos(paren());
  175.     if (eq(n, func, "atan"))    return atan(paren());
  176.     if (eq(n, func, "atan2"))    {paren2(&x, &y); return atan2(x, y);}
  177.  
  178.     if (eq(n, func, "sind"))    return sin(DEG_TO_RAD(paren()));
  179.     if (eq(n, func, "cosd"))    return cos(DEG_TO_RAD(paren()));
  180.     if (eq(n, func, "tand"))    return tan(DEG_TO_RAD(paren()));
  181.     if (eq(n, func, "dasin"))    return RAD_TO_DEG(asin(paren()));
  182.     if (eq(n, func, "dacos"))    return RAD_TO_DEG(acos(paren()));
  183.     if (eq(n, func, "datan"))    return RAD_TO_DEG(atan(paren()));
  184.     if (eq(n, func, "datan2"))    {paren2(&x, &y);
  185.                     return RAD_TO_DEG(atan2(x, y));}
  186.  
  187.     if (eq(n, func, "floor"))    return floor(paren());
  188.     if (eq(n, func, "ceil"))    return ceil(paren());
  189.  
  190.     error(func, n, "bad numerical expression");
  191.     return 0.;
  192.     }
  193.  
  194.     error(s, 1, "syntax error");
  195.     return 0.;
  196. }
  197.  
  198. /* paren: '(' expr ')' */
  199.  
  200. static double paren()
  201. {
  202.     double x;
  203.  
  204.     space();
  205.     if (*s!='(') error(s, 1, "expected '('");
  206.     s++;
  207.     x = expr();
  208.     space();
  209.     if (*s!=')') error(s, 1, "expected ')'");
  210.     s++;
  211.     return x;
  212. }
  213.  
  214. /* paren2: '(' expr ',' expr ')' */
  215.  
  216. static paren2(
  217.     double *x, double *y)
  218. {
  219.     space();
  220.     if (*s!='(') error(s, 1, "expected '('");
  221.     s++;
  222.     *x = expr();
  223.     space();
  224.     if (*s!=',') error(s, 1, "expected ','");
  225.     s++;
  226.     *y = expr();
  227.     space();
  228.     if (*s!=')') error(s, 1, "expected ')'");
  229.     s++;
  230. }
  231.  
  232. /*
  233.  * posconst: given a string beginning at s, return floating point value.
  234.  * like atof but it uses and modifies the global ptr s
  235.  */
  236.  
  237. static double posconst()
  238. {
  239.     int base, exp, pos, d;
  240.     double x, y;
  241.  
  242.     space();
  243.     if (*s=='0') {        /* change base: 10 = 012 = 0xa = 0b2:1010 */
  244.     s++;
  245.     switch (*s) {
  246.         case 'b':
  247.         s++;
  248.         for (base=0; isdigit(*s); s++)
  249.             base = base*10+*s-'0';    /* base is in base 10! */
  250.         if (*s!=':') error(s, 1, "expecting ':'");
  251.         s++;
  252.         break;
  253.         case 'x': s++; base = 16; break;
  254.         case 't': s++; base = 10; break;
  255.         case '.': base = 10; break;        /* a float, e.g.: 0.123 */
  256.         default:  base = 8; break;
  257.     }
  258.     }
  259.     else base = 10;
  260.  
  261.     x = 0.;
  262.     for (; d = digit(*s), d>=0 && d<base; s++)
  263.     x = x*base+d;
  264.     if (*s=='.') {
  265.     s++;
  266.     for (y=1.; d = digit(*s), d>=0 && d<base; s++) {
  267.         x = x*base+d;        /* fraction is in variable base */
  268.         y *= base;
  269.     }
  270.     x /= y;
  271.     }
  272.     if (*s=='e' || *s=='E') {
  273.     s++;
  274.     if (*s=='-')       {s++; pos = 0;}
  275.     else if (*s=='+') {s++; pos = 1;}
  276.     else pos = 1;
  277.     for (exp=0; isdigit(*s); s++)
  278.         exp = exp*10+*s-'0';    /* exponent is in base 10 */
  279.     y = expt(base, exp);
  280.     if (pos) x *= y;
  281.     else x /= y;
  282.     }
  283.     return x;
  284. }
  285.  
  286. static digit(
  287.     int c)
  288. {
  289.     return isdigit(c) ? c-'0' :
  290.     c>='a'&&c<='z' ? c-'a'+10 : c>='A'&&c<='Z' ? c-'A'+10 : -1;
  291. }
  292.  
  293. /* expt: a^n for n>=0 */
  294.  
  295. static double expt(a, n)
  296. int a, n;
  297. {
  298.     double t, x;
  299.  
  300.     if (n<0) {
  301.     fprintf(stderr, "expt: can't do negative exponents\n");
  302.     return 1.;
  303.     }
  304.     if (n==0) return 1.;
  305.     for (t=a, x=1.; n>0; n>>=1) {
  306.     if (n&1) x *= t;
  307.     t *= t;
  308.     }
  309.     return x;
  310. }
  311.  
  312. /* eq: test equality of string a, of length n, with null-terminated string b */
  313.  
  314. static eq(
  315.     int n,
  316.     char *a, char *b)
  317. {
  318.     char c;
  319.     int ret;
  320.  
  321.     c = a[n];
  322.     a[n] = 0;
  323.     ret = str_eq(a, b);
  324.     a[n] = c;
  325.     return ret;
  326. }
  327.  
  328. static error(
  329.     char *s, 
  330.     int len,
  331.     char *err)
  332. {
  333.     if (*s==0) s[len] = 0;    /* just in case */
  334.     printf("expr: %s: ", err);
  335.     prints(s-s0, s0);
  336.     printf("[");
  337.     prints(len, s);
  338.     printf("]");
  339.     prints(s+strlen(s)-s0-len, s+len);
  340.     printf("\n");
  341.     if (expr_error!=EXPR_BAD)
  342.     expr_error = s==s0 ? EXPR_BAD : EXPR_SOSO;
  343. }
  344.  
  345. /* prints: print string s of length n */
  346.  
  347. static prints(
  348.     int n,
  349.     char *s)
  350. {
  351.     char c;
  352.  
  353.     c = s[n];
  354.     s[n] = 0;
  355.     printf("%s", s);
  356.     s[n] = c;
  357. }
  358.